package com.fy.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.fy.common.exception.JWTParseException;
import com.fy.common.vo.ApiRest;
import com.fy.module.sys.entity.UserMsg;
import com.fy.utils.JwtUtils;
import com.fy.utils.RsaUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.ResourceUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.PublicKey;
import java.util.List;

/**
 * 江迪
 */
public class JWTVerifyFilter extends BasicAuthenticationFilter {

    public JWTVerifyFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    //重写dofilterInternal方法
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //自定义实现登录拦截的逻辑


        //放行登陆
        if("/user/login".equals(request.getRequestURI())){
            chain.doFilter(request, response);
            return;
        }

        //放行token验证
        if("/user/checkToken".equals(request.getRequestURI())){
            chain.doFilter(request,response);
            return;
        }

        //放行OPTIONS
        if("OPTIONS".equals(request.getMethod())){
            chain.doFilter(request, response);
            return;
        }
        //验证码放行
        if("/verify".equals(request.getRequestURI())){
            chain.doFilter(request, response);
            return;
        }

        //当该放行的放行完之后，接下来便是需要验证token的请求

        //1、首先获取token令牌
        String token = request.getHeader("token");
        //token非空判断
        if(StrUtil.isEmpty(token)){
            //响应客户端
            responseClient(ApiRest.success("token令牌不能为空"),response,HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        //2、检查令牌是否合法
        PublicKey publicKey =null;
        try {
            //调用RsaUtils获取工具类
            publicKey=RsaUtils.getPublicKey(ResourceUtils.getFile("classpath:pub").getPath());

            //通过JWTUtils解析token令牌，获取里面的用户信息
            UserMsg user = (UserMsg) JwtUtils.getInfoFromToken(token, publicKey, UserMsg.class);

            //通过解析出来的对象获取其权限信息
            String roleNamesAndPermNames = user.getRoleNamesAndPermNames();
            List<GrantedAuthority> authorityList = AuthorityUtils.commaSeparatedStringToAuthorityList(roleNamesAndPermNames);

            //获取到用户权限信息之后，将其丢入到securityContext中，用来判断用户是否登录
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken=new UsernamePasswordAuthenticationToken(user,null,authorityList);
            //存入到securityContext上下文中
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            //放行资源
            chain.doFilter(request,response);
        } catch (Exception e) {
           //处理异常信息，根据异常类，抛出不同的异常信息
            if(e instanceof JWTParseException){
                responseClient(ApiRest.failure(e.getMessage(),null),response,HttpServletResponse.SC_UNAUTHORIZED);
                return;
            }else {
                responseClient(ApiRest.failure(e.getMessage(),null),response,HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return;
            }
        }

    }

    //响应给客户端的数据
    private void responseClient(ApiRest apiRest,HttpServletResponse response,int status){
        //设置json数据格式
        response.setContentType("application/json:charset=utf-8");
        //设置响应状态码
        response.setStatus(status);
        //通过打印流将apiRest写出去
        PrintWriter writer=null;
        try {
           writer= response.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //将apiRest写到客户端
        writer.write(JSONUtil.toJsonStr(apiRest));
        //关闭资源
        writer.close();
    }
}
